package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.ApArticleConfigMapper;
import com.heima.article.mapper.ApArticleContentMapper;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.mapper.ApAuthorMapper;
import com.heima.article.service.ApArticleService;
import com.heima.article.service.GeneratePageService;
import com.heima.common.constants.article.ArticleConstants;
import com.heima.common.constants.message.NewsUpOrDownConstants;
import com.heima.common.excpetion.CustException;
import com.heima.feign.admin.AdminFeign;
import com.heima.feign.wemedia.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleHomeDTO;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.article.pojos.ApArticleContent;
import com.heima.model.article.pojos.ApAuthor;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import io.seata.common.util.StringUtils;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service("ArticleService")
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    @Value("${file.oss.web-site}")
    private String webSite;

    @Value("${file.oss.prefix}")
    String prefix;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RabbitTemplate rabbitTemplate;





    @Autowired
    GeneratePageService generatePageService;

    /**
     * 保存或修改文章
     *
     * @param newsId 文章id
     * @return 操作结果
     */
    @GlobalTransactional
    @Override
    public boolean publishArticle(Integer newsId) {
        //根据文章Id查询文章
        WmNews wmNews = this.getWmNews(newsId);
        //封装文章详细信息对象
        ApArticle article = this.getArticle(wmNews);
        //初始文章关联信息
        this.operationArticle(article);
        //保存关联配置和内容配置
        this.saveConfigAndContent(wmNews, article);

        // 页面静态化
        generatePageService.generateArticlePage(wmNews.getContent(), article);

        //更新wmNews状态为9已发布 并设置articleId
        this.updateWmNewsStatus(wmNews, article.getId());

        // 通知ES索引库添加文章索引
        rabbitTemplate.convertAndSend(NewsUpOrDownConstants.NEWS_UP_FOR_ES_QUEUE, article.getId());

        return true;
    }

    @Autowired
    WemediaFeign wemediaFeign;

    @Override
    public WmNews getWmNews(Integer newsId) {
        ResponseResult<WmNews> news = wemediaFeign.findWmNewsById(newsId);
        if (!news.checkCode())
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR, "调用微服务失败...");
        WmNews wmNews = news.getData();
        if (wmNews == null)
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "调用微服务查询数据失败...");
        //判断文章状态是不是待发布状态(4或8)
        int status = wmNews.getStatus();
        if (status != WmNews.Status.ADMIN_SUCCESS.getCode() && status != WmNews.Status.SUCCESS.getCode()) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "数据不允许这种操作...");
        }

        return wmNews;
    }

    @Autowired
    AdminFeign adminFeign;

    @Autowired
    ApAuthorMapper authorMapper;

    /**
     * 根据文章对象封装文章详细信息对象
     *
     * @param wmNews
     * @return
     */
    @Override
    public ApArticle getArticle(WmNews wmNews) {
        ApArticle article = new ApArticle();
        // 去除图片前缀
        String resultURL = this.urlToStr(wmNews.getImages());
        wmNews.setImages(resultURL);

        BeanUtils.copyProperties(wmNews, article);

        article.setId(wmNews.getArticleId());
        article.setFlag((byte) 0);
        article.setLayout(wmNews.getType());
        //远程查询频道信息
        ResponseResult<AdChannel> result = adminFeign.findOne(article.getChannelId());
        if (!result.checkCode())
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR, "调用微服务失败...");
        //获取数据
        AdChannel adChannel = result.getData();
        if (adChannel == null)
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "调用微服务查询数据失败...");

        //存入频道名称
        article.setChannelName(adChannel.getName());
        //根据 自媒体用户Id查询作者信息
        ApAuthor apAuthor = authorMapper.selectOne(Wrappers.<ApAuthor>lambdaQuery().eq(ApAuthor::getWmUserId, wmNews.getUserId()));
        if (apAuthor == null)
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        //设置作者ID信息
        article.setAuthorId(Long.valueOf(apAuthor.getId()));
        article.setAuthorName(apAuthor.getName());

        return article;
    }

    @Autowired
    ApArticleConfigMapper apArticleConfigMapper;

    @Autowired
    ApArticleContentMapper apArticleContentMapper;

    /**
     * 保存文章配置信息和详细信息
     *
     * @param article
     */
    @Override
    public void saveConfigAndContent(WmNews wmNews, ApArticle article) {
        //添加文章配置信息
        ApArticleConfig apArticleConfig = new ApArticleConfig();
        apArticleConfig.setArticleId(article.getId());
        apArticleConfig.setIsComment(true);
        apArticleConfig.setIsForward(false);
        apArticleConfig.setIsDown(false);
        apArticleConfig.setIsDelete(false);
        apArticleConfigMapper.insert(apArticleConfig);
        //添加文章详情
        ApArticleContent apArticleContent = new ApArticleContent();
        apArticleContent.setArticleId(article.getId());
        apArticleContent.setContent(wmNews.getContent());
        apArticleContentMapper.insert(apArticleContent);
    }

    @Autowired
    ApArticleMapper apArticleMapper;

    /**
     * 初始化文章关联信息
     *
     * @param article
     */
    @Override
    public void operationArticle(ApArticle article) {
        //判断wmNews是否已经关联了文章详情
        if (article.getId() == null) {
            //没有关联 ->初始化文章详细信息
            article.setCollection(0); //收藏数
            article.setLikes(0); //点赞数
            article.setComment(0);
            article.setViews(0);
            apArticleMapper.insert(article);
        } else {
            //已经关联 ->修改文章详细信息 ->删除关联关系
            ApAuthor apAuthor = authorMapper.selectById(article.getAuthorId());
            if (apAuthor == null)
                CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
            // TODO 未知问题待解决
            //修改
//            authorMapper.updateById(apAuthor);

            //删除关联关系
            apArticleConfigMapper.delete(Wrappers.<ApArticleConfig>lambdaQuery().eq(ApArticleConfig::getArticleId, article.getId()));
            apArticleContentMapper.delete(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, article.getId()));
        }
    }

    /**
     * 更新文章状态为已发布
     *
     * @param wmNews
     */
    @Override
    public void updateWmNewsStatus(WmNews wmNews, Long articleId) {
        wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
        wmNews.setArticleId(articleId);
        //调用Feign更新文章
        ResponseResult responseResult = wemediaFeign.updateWmNews(wmNews);

        if (!responseResult.checkCode())
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR, "更新WmNews失败...");
    }

    @Value("${file.minio.readPath}")
    String readPath;

    /**
     * 根据参数加载文章列表
     *
     * @param loadType 0为加载更多  1为加载最新
     * @param dto
     * @return
     */
    @Override
    public ResponseResult load(Short loadType, ArticleHomeDTO dto) {
        // 判断入参合法性并初始化值
        {
            if (dto == null || loadType == null || dto.getSize() == null)
                CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);

            if (!loadType.equals(ArticleConstants.LOADTYPE_LOAD_MORE) && !loadType.equals(ArticleConstants.LOADTYPE_LOAD_NEW))
                CustException.cust(AppHttpCodeEnum.PARAM_INVALID);

            //如果传入的频道为空则返回默认频道数据
            if (StringUtils.isBlank(dto.getTag()))
                dto.setTag(ArticleConstants.DEFAULT_TAG);

            if (dto.getMaxBehotTime() == null)
                dto.setMaxBehotTime(new Date());

            if (dto.getMinBehotTime() == null)
                dto.setMinBehotTime(new Date());
        }
        //查询文章列表
        List<ApArticle> apArticles = apArticleMapper.loadArticleList(dto, loadType);

        //批量加上前缀
        for (ApArticle apArticle : apArticles) {
            //添加minio前缀
            apArticle.setStaticUrl(readPath + apArticle.getStaticUrl());
            //添加图片链接前缀
            apArticle.setImages(strToImages(apArticle.getImages()));
        }

        //封装返回对象
        ResponseResult responseResult = ResponseResult.okResult(apArticles);
        responseResult.setHost(webSite);

        return responseResult;
    }

    /**
     * 根据参数加载文章列表  v2
     *
     * @param loadType  读取的类别
     * @param dto       文章首页dto
     * @param firstPage 第一页
     * @return 文章列表
     */
    @Override
    public ResponseResult load2(Short loadType, ArticleHomeDTO dto, boolean firstPage) {
        if (firstPage) {
            // redis
            String articleListJson = (String) redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + dto.getTag());
            if (StringUtils.isNotBlank(articleListJson)) {
                List<ApArticle> apArticles = JSON.parseArray(articleListJson, ApArticle.class);
                for (ApArticle apArticle : apArticles) {
                    apArticle.setStaticUrl(readPath + apArticle.getStaticUrl());
                }
                ResponseResult result = ResponseResult.okResult(apArticles);
                result.setHost(webSite);

                return result;
            }
        }

        return load(loadType, dto);
    }

    /**
     * 加上图片前缀
     *
     * @param target 数据库中图片url字符串
     */
    private String strToImages(String target) {
        return Arrays.stream(target.split(",")).map(s -> webSite + s).collect(Collectors.joining(","));
    }

    /**
     * 去除图片前缀
     */
    private String urlToStr(String target) {
        String[] split = target.split(",");
        return Arrays.stream(split)  // 获取流
                .map((url) -> url.replace(webSite, ""))  // 对流数据的中间操作
                .collect(Collectors.joining(","));
    }
}
